local table_insert = table.insert
local table_sort = table.sort
local table_remove = table.remove
local math_floor = math.floor
local table_unpack = table.unpack
local math_random = math.random
math.randomseed(os.time())
local util = require "util"
local error_code = require "error_code"
local constant = require "constant"

local M = {}

local MAX_BETTING_COINS = 1000000000    --单个人押注上限

local GAME_STATUS_INIT = 0          --初始化状态
local GAME_STATUS_STARTED = 1       --游戏开始
local GAME_STATUS_BETTING = 2       --押注
local GAME_STATUS_OVER = 3          --结束状态


local BIG_BAOSHIJIE    = 1      --大保时捷
local SMALL_BAOSHIJIE  = 2      --小保时捷
local BIG_BENCHI    = 3        --大奔驰
local SMALL_BENCHI  = 4         --小奔驰
local BIG_BAOMA     = 5         --大宝马
local SMALL_BAOMA   = 6         --小宝马
local BIG_DAZHONG   = 7         --大大众
local SMALL_DAZHONG = 8         --小大众
-------------------------------------------------------


local MT_INDEX = {}

--可下注列表
local AVAILABLE_BETTING_COINS_MAP = {
    [100] = true,
    [1000] = true,
    [5000] = true,
    [10000] = true,
    [50000] = true,
}

local BETTING_SIDE_RATE_MAP = {
    [SMALL_DAZHONG] = 5,
    [BIG_DAZHONG] = 10,
    [SMALL_BAOMA] = 5,
    [BIG_BAOMA] = 20,
    [SMALL_BENCHI] = 5,
    [BIG_BENCHI] = 30,
    [SMALL_BAOSHIJIE] = 5,
    [BIG_BAOSHIJIE] = 40,
}

function MT_INDEX:init()
    self.game_status = GAME_STATUS_INIT

    self.betting_list = {
        [SMALL_DAZHONG] = 0,
        [BIG_DAZHONG] = 0,
        [SMALL_BAOMA] = 0,
        [BIG_BAOMA] = 0,
        [SMALL_BENCHI] = 0,
        [BIG_BENCHI] = 0,
        [SMALL_BAOSHIJIE] = 0,
        [BIG_BAOSHIJIE] = 0,
    }

    self.player_betting_map = {}            --当前游戏中的玩家列表
    self.game_result = nil
    self.betting_list_no_robot = {
        [SMALL_DAZHONG] = 0,
        [BIG_DAZHONG] = 0,
        [SMALL_BAOMA] = 0,
        [BIG_BAOMA] = 0,
        [SMALL_BENCHI] = 0,
        [BIG_BENCHI] = 0,
        [SMALL_BAOSHIJIE] = 0,
        [BIG_BAOSHIJIE] = 0,
    }

    self.robot_betting_list = {
        [SMALL_DAZHONG] = {},
        [BIG_DAZHONG] = {},
        [SMALL_BAOMA] = {},
        [BIG_BAOMA] = {},
        [SMALL_BENCHI] = {},
        [BIG_BENCHI] = {},
        [SMALL_BAOSHIJIE] = {},
        [BIG_BAOSHIJIE] = {},
    }
    return true
end

function MT_INDEX:check_bet_num(player_list,player_not_bet_num)
    local ret5 = {}
    local ret4 = {}
    for uid,info in pairs(player_list) do
        if not self.player_betting_map[uid] then
            player_not_bet_num[uid] = player_not_bet_num[uid] or 0
            player_not_bet_num[uid] = player_not_bet_num[uid] + 1
            if player_not_bet_num[uid] >= 5 then
                table_insert(ret5,uid)
            end
            if player_not_bet_num[uid] == 4 then
                table_insert(ret4,uid)
            end
        else
            player_not_bet_num[uid] = 0 
        end
    end
    for uid,num in pairs(player_not_bet_num) do
        if not player_list[uid] then
            player_not_bet_num[uid] = nil
        end
    end    
    return ret5,ret4
end

function MT_INDEX:get_betting_list_no_robot()
    return self.betting_list_no_robot
end

function MT_INDEX:get_side_player_bet_list(side)
    --print("self.player_betting_map====",side,tostring_r(self.player_betting_map))
    local side_bet_list = {}
    for uid,records in pairs(self.player_betting_map) do
        --print("self.player_betting_map====22",uid,records[side],tostring_r(records[side]))
        if records[side] then
            table_insert(side_bet_list,{uid = uid,bet_coins = records[side].coins or 0})
        end
    end

    return side_bet_list
end

function MT_INDEX:get_side_betting_total_coins(side)
    return self.betting_list[side] or 0
end

function MT_INDEX:get_player_side_bet_coins(side)
    return self.betting_list_no_robot[side] or 0
end

function MT_INDEX:get_side_robot_type_betting_coins(side,coins_type)
    return self.robot_betting_list[side][coins_type] or 0
end

function MT_INDEX:get_total_betting_coins()
    local total_coins = 0
    for side,coins in pairs(self.betting_list) do
        total_coins = total_coins + coins
    end
    return total_coins
end

function MT_INDEX:start_game()
    assert(self.game_status == GAME_STATUS_INIT)
    self.game_status = GAME_STATUS_STARTED

    return true
end

function MT_INDEX:is_side_limit(side,coins,self_table_type)
    local roomdata = global_configs.roomdata[self_table_type]
    --if not roomdata then return false end
    --dbglog("is_side_limit side ",side,"coins:",coins,self.betting_list[side],"self_table_type",self_table_type)
    if roomdata.all_times_5_limit and roomdata.all_times_5_limit ~= 0 then
        if side == SMALL_BAOSHIJIE and self.betting_list[SMALL_BAOSHIJIE] + coins > roomdata.all_times_5_limit then 
            return true
        end   
        if side == SMALL_BENCHI and self.betting_list[SMALL_BENCHI] + coins > roomdata.all_times_5_limit then 
            return true
        end  
        if side == SMALL_BAOMA and self.betting_list[SMALL_BAOMA] + coins > roomdata.all_times_5_limit then 
            return true
        end  
        if side == SMALL_DAZHONG and self.betting_list[SMALL_DAZHONG] + coins > roomdata.all_times_5_limit then 
            return true
        end  
    end
    if roomdata.all_times_10_limit and roomdata.all_times_10_limit ~= 0 and side == BIG_DAZHONG and self.betting_list[BIG_DAZHONG] + coins > roomdata.all_times_10_limit then
        return true
    end
    if roomdata.all_times_20_limit and roomdata.all_times_20_limit ~= 0 and side == BIG_BAOMA and self.betting_list[BIG_BAOMA] + coins > roomdata.all_times_20_limit then
        return true
    end
    if roomdata.all_times_30_limit and roomdata.all_times_30_limit ~= 0 and side == BIG_BENCHI and self.betting_list[BIG_BENCHI] + coins > roomdata.all_times_30_limit then
        return true
    end
    if roomdata.all_times_40_limit and roomdata.all_times_40_limit ~= 0 and side == BIG_BAOSHIJIE and self.betting_list[BIG_BAOSHIJIE] + coins > roomdata.all_times_40_limit then
        return true
    end

    return false
end

function MT_INDEX:is_personal_limit(uid,side,coins,self_table_type)
    --dbglog("self_table_type",self_table_type)
    local roomdata = global_configs.roomdata[self_table_type]
    if not roomdata or not roomdata.person_limit then return false end

    if roomdata.person_limit[1] ~= 0 and coins < roomdata.person_limit[1] then 
        return true
    end
    local all_coins = coins
    local records = self.player_betting_map[uid] or {}
    for side,info in pairs(records) do
        all_coins = all_coins + info.coins
    end
    if roomdata.person_limit[2] ~= 0 and all_coins > roomdata.person_limit[2] then
        return true
    end

    return false
end

function MT_INDEX:is_personal_side_limit(uid,side,coins,self_table_type)
    --dbglog("self_table_type",self_table_type)
    local roomdata = global_configs.roomdata[self_table_type]
    if not roomdata then return false end
    local records = self.player_betting_map[uid] or {}

    if roomdata.times_5_limit ~= 0 then
        if side == SMALL_BAOSHIJIE and records[SMALL_BAOSHIJIE] and records[SMALL_BAOSHIJIE].coins + coins > roomdata.times_5_limit then 
            return true
        end   
        if side == SMALL_BENCHI and records[SMALL_BENCHI] and records[SMALL_BENCHI].coins + coins > roomdata.times_5_limit then 
            return true
        end  
        if side == SMALL_BAOMA and records[SMALL_BAOMA] and records[SMALL_BAOMA].coins + coins > roomdata.times_5_limit then 
            return true
        end  
        if side == SMALL_DAZHONG and records[SMALL_DAZHONG] and records[SMALL_DAZHONG].coins + coins > roomdata.times_5_limit then 
            return true
        end  
    end
    if roomdata.times_10_limit ~= 0 and side == BIG_DAZHONG and records[BIG_DAZHONG] and records[BIG_DAZHONG].coins + coins > roomdata.times_10_limit then
        return true
    end
    if roomdata.times_20_limit ~= 0 and side == BIG_BAOMA and records[BIG_BAOMA] and records[BIG_BAOMA].coins + coins > roomdata.times_20_limit then
        return true
    end
    if roomdata.times_30_limit ~= 0 and side == BIG_BENCHI and records[BIG_BENCHI] and records[BIG_BENCHI].coins + coins > roomdata.times_30_limit then
        return true
    end
    if roomdata.times_40_limit ~= 0 and side == BIG_BAOSHIJIE and records[BIG_BAOSHIJIE] and records[BIG_BAOSHIJIE].coins + coins > roomdata.times_40_limit then
        return true
    end
    return false
end

function MT_INDEX:get_my_betting_list(uid)
    local player_betting_map = self.player_betting_map
    local records = player_betting_map[uid]
    if not records then
        return
    end
    
    local ret = {}
    for side,info in pairs(records) do
        ret[side] = info.coins
    end
    
    return ret
end

function MT_INDEX:get_player_bet_coins()
    local player_coins_map = {}
    for uid,records in pairs(self.player_betting_map) do
        local player_coins = 0
        for _,t in pairs(records) do
            player_coins = player_coins + t.coins
        end
        player_coins_map[uid] = player_coins
    end

    return player_coins_map
end

function MT_INDEX:is_available_betting(coins,available_betting_list) --押注金额是否有效
    for i = 1,#available_betting_list do
        if available_betting_list[i] == coins then
            return true
        end
    end
    return false
end

local function can_bet(self,uid,side,coins,available_betting_list,bet_type,self_table_type)
   -- print("can_bet==============",uid,side,coins,tostring_r(available_betting_list))
    if bet_type ~= constant.BET_TYPE_CONTINUE and not self:is_available_betting(coins,available_betting_list) then
        print("1233213214325555555555555")
        return false,-303
    end

    if not BETTING_SIDE_RATE_MAP[side] then
        return false,-301
    end

    -- local player_betting_map = self.player_betting_map
    -- local records = player_betting_map[uid]
    -- if not records then
    --     return true
    -- end

    if self:is_side_limit(side,coins,self_table_type) then
        dbglog("error is_side_limit side ",side,coins)
        return false, error_code.SIDE_BET_LIMIT
    end

    if self:is_personal_side_limit(uid,side,coins,self_table_type) then
        dbglog("error is_side_limit side ",side,coins)
        return false, error_code.PERSONAL_SIDE_BET_LIMIT
    end

    if self:is_personal_limit(uid,side,coins,self_table_type) then
        dbglog("error is_side_limit side ",side,coins)
        return false, error_code.PERSONAL_BET_LIMIT
    end

    return true
end

MT_INDEX.can_bet = can_bet

function MT_INDEX:bet(uid,side,coins,is_robot,player_info,bet_type,self_table_type)
    local ok,ret = can_bet(self,uid,side,coins,player_info.available_betting_list,bet_type,self_table_type)
    if not ok then
        return false,ret
    end

    local player_betting_map = self.player_betting_map
    player_betting_map[uid] = player_betting_map[uid] or {}
    local records = player_betting_map[uid]
    records[side] = records[side] or {coins = 0}
    local r = records[side]   
    local curr_coins = r.coins 
    r.coins = curr_coins + coins

    local side_coins = self.betting_list[side] + coins
    self.betting_list[side] = side_coins
   -- dbglog("is_side_limit side ",side,coins,side_coins)
    --非机器人进行累计
    if not is_robot then
        print("bet111111111111111111111",uid,coins,is_robot)
        self.betting_list_no_robot[side] = self.betting_list_no_robot[side] + coins
    else
        local coins_type = player_info.coins_type
        self.robot_betting_list[side][coins_type] = (self.robot_betting_list[side][coins_type] or 0) + coins 
    end

    return true,{
        side_coins = side_coins,
        my_side_coins = r.coins,
    }
end

function MT_INDEX:start_betting()
    assert(self.game_status == GAME_STATUS_STARTED)
    self.game_status = GAME_STATUS_BETTING
    return true
end

function MT_INDEX:is_betting()
    return self.game_status == GAME_STATUS_BETTING
end

function MT_INDEX:is_game_over()
    return self.game_status == GAME_STATUS_OVER
end

function MT_INDEX:get_betting_uid_list()
    local betting_uid_list = {}
    for uid,_ in pairs(self.player_betting_map) do
        table_insert(betting_uid_list,uid)
    end
    return betting_uid_list
end

function MT_INDEX:get_all_betting_list()
    local ret = {}
    for side,coins in pairs(self.betting_list) do
        if coins > 0 then
            ret[side] = coins
        end
    end
    
    return ret
end    

function MT_INDEX:get_my_total_betting_coins(uid)
    local total_coins = 0
    local my_betting_list = self:get_my_betting_list(uid)
    for side,coins in pairs(my_betting_list) do
        total_coins = total_coins + coins
    end
    return total_coins
end

local function copy_table(t)
    local new_t = {}
    for k,v in pairs(t) do
        new_t[k] = v
    end
    return new_t
end

function MT_INDEX:judge_result(fee_percent,affect_side)
    assert(self.game_status == GAME_STATUS_BETTING)
    self.game_status = GAME_STATUS_OVER

    --加入到比牌列表中
    print("judge_result",fee_percent,affect_side)

    if not affect_side then
        affect_side = math_random(1,8)
    end
    
    local uid_result_map = {}   --玩家净输赢列表，减去押注的输赢
    local pay_fee_map = {}      --台费列表
    local winner_coin_map = {}  --赢的金币列表，不减去押注的输赢
    local player_side_map = {}

   -- print("=============self.player_betting_map",tostring_r(self.player_betting_map))
    for uid,records in pairs(self.player_betting_map) do
        player_side_map[uid] = {}

        local r =  records[affect_side] or {coins = 0}
        local coins = r.coins or 0
        local winner_coins = coins * BETTING_SIDE_RATE_MAP[affect_side]
        local betting_coins = self:get_my_total_betting_coins(uid)
        if winner_coins - coins > 0 then
            pay_fee_map[uid] = math_floor((winner_coins - coins) * fee_percent)
        end
        uid_result_map[uid] = winner_coins - betting_coins - (pay_fee_map[uid] or 0)
        winner_coin_map[uid] = winner_coins - (pay_fee_map[uid] or 0)

        for side,data in pairs(records) do
            local r = records[side] or {coins = 0}
            local coins = r.coins or 0
            if side == affect_side then
                local win_coins = coins * BETTING_SIDE_RATE_MAP[affect_side]
                table_insert(player_side_map[uid],{side = side,result_coins = win_coins})
            else
                table_insert(player_side_map[uid],{side = side,result_coins = -coins})
            end
        end
    end
    local winner_side = affect_side
    self.game_result = {
        winner_side       = winner_side,
        uid_result_map  = uid_result_map,
        pay_fee_map       = pay_fee_map,
        winner_coin_map   = winner_coin_map,
        position = math_random(0,3),
        player_side_map = player_side_map,
    }
    dbglog("bcbm_game_result",winner_side)

    return true
end

function MT_INDEX:get_game_result()
    assert(self.game_status == GAME_STATUS_OVER)
    return self.game_result
end

M.AVAILABLE_BETTING_COINS_MAP = AVAILABLE_BETTING_COINS_MAP
M.BETTING_SIDE_RATE_MAP = BETTING_SIDE_RATE_MAP
M.RICH_SEAT_SIDE = 1
M.LUCK_SEAT_SIDE = 4

function M.new()
    local o = {}
    return setmetatable(o,{__index = MT_INDEX})
end

return M